package response

import (
	"MoSkeleton/framework/core/consts"
	"MoSkeleton/framework/core/moerrors"
	"MoSkeleton/framework/core/translater"
	"MoSkeleton/framework/utils"
	"bytes"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"mime"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"
)

type Response struct {
	Code int         `json:"code"`
	Data interface{} `json:"data"`
	Msg  string      `json:"msg"`
}

var (
	comparedValidatedMsgError = (*moerrors.ValidateMsgError)(nil)
)

func ReturnJson(Context *gin.Context, httpCode int, dataCode int, msg string, data interface{}) {

	//Context.Header("key2020","value2020")  	//可以根据实际情况在头部添加额外的其他信息
	Context.JSON(httpCode, gin.H{
		"code": dataCode,
		"msg":  msg,
		"data": data,
	})
}

// ReturnJsonFromString 将json字符窜以标准json格式返回（例如，从redis读取json格式的字符串，返回给浏览器json格式）
func ReturnJsonFromString(Context *gin.Context, httpCode int, jsonStr string) {
	Context.Header("Content-Type", "application/json; charset=utf-8")
	Context.String(httpCode, jsonStr)
}

func SuccessFileDataWithContentType(c *gin.Context, filename, contentType string, buf *bytes.Buffer) {
	// 设置响应头
	encodedFilename := url.PathEscape(filename)
	encodedFilename = strings.ReplaceAll(encodedFilename, " ", "_")
	encodedFilename = strings.ReplaceAll(encodedFilename, "\"", "")
	encodedFilename = strings.ReplaceAll(encodedFilename, "\\", "")

	c.Header("Content-Disposition", "attachment; filename*=UTF-8''"+encodedFilename)
	c.Header("Access-Control-Expose-Headers", "Content-Disposition")
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Content-Type", contentType)
	// 设置 Cache-Control 和 Pragma 头以避免缓存
	c.Header("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0")
	c.Header("Pragma", "no-cache")
	c.Header("Expires", "0")

	// 返回 文件数据
	c.Data(http.StatusOK, contentType, buf.Bytes())
}

func SuccessWithFileData(c *gin.Context, filename string, buf *bytes.Buffer) {
	contentType := mime.TypeByExtension(filepath.Ext(filename))
	if contentType == "" {
		contentType = "application/octet-stream"
	}
	SuccessFileDataWithContentType(c, filename, contentType, buf)
}

// 语法糖函数封装

// Success 直接返回成功
func Success(c *gin.Context, msg string, data interface{}) {
	ReturnJson(c, http.StatusOK, consts.CommStatusOkCode, msg, data)
}

func SuccessAsI18n(c *gin.Context, tkey string, data interface{}) {
	msg, _ := utils.Translater.Translate(tkey)
	Success(c, msg, data)
}

func SuccessWithDataCodeAsI18n(c *gin.Context, dataCode int, tkey string, data interface{}) {
	msg, _ := utils.Translater.Translate(tkey)
	SuccessWithDataCode(c, dataCode, msg, data)
}

func SuccessWithDataCode(c *gin.Context, dataCode int, msg string, data interface{}) {
	ReturnJson(c, http.StatusOK, dataCode, msg, data)
}

// Fail 失败的业务逻辑
func Fail(c *gin.Context, dataCode int, msg string, data interface{}) {
	ReturnJson(c, http.StatusBadRequest, dataCode, msg, data)
	c.Abort()
}

func FailMsg(c *gin.Context, dataCode int, msg string) {
	ReturnJson(c, http.StatusOK, dataCode, msg, "")
	c.Abort()
}

func FailMsgAsI18n(c *gin.Context, dataCode int, tkey string) {
	msg, _ := utils.Translater.Translate(tkey)
	FailMsg(c, dataCode, msg)
}

func FailValidateError(c *gin.Context, err *moerrors.ValidateMsgError) {
	FailMsg(c, err.Code, err.Msg)
}

// 如果err 非 ValidateMsgError实例，则返回 exceptMsg
func FailError(c *gin.Context, err error, exceptMsg string) {
	if errors.Is(err, comparedValidatedMsgError) {
		moErr := err.(*moerrors.ValidateMsgError)
		if moErr.Msg == "" {
			moErr.Msg = exceptMsg
		}
		FailValidateError(c, moErr)
	} else {
		FailMsg(c, consts.ServerOccurredErrorCode, exceptMsg)
	}
}

func FailErrorWithCodeAsI18n(c *gin.Context, err error, exceptCode int, tkey string) {
	msg, _ := utils.Translater.Translate(tkey)
	FailErrorWithCode(c, err, exceptCode, msg)
}

// 如果err 非 ValidateMsgError实例，则返回 exceptMsg
func FailErrorWithCode(c *gin.Context, err error, exceptCode int, exceptMsg string) {
	if errors.Is(err, comparedValidatedMsgError) {
		moErr := err.(*moerrors.ValidateMsgError)
		if moErr.Msg == "" {
			moErr.Msg = exceptMsg
		}
		if moErr.Code == 0 {
			moErr.Code = exceptCode
		}
		FailValidateError(c, moErr)
	} else {
		FailMsg(c, exceptCode, exceptMsg)
	}
}

// ErrorTokenBaseInfo token 基本的格式错误
func ErrorTokenBaseInfo(c *gin.Context) {
	errMsg, _ := utils.Translater.Translate(consts.TKey_ErrorsTokenBaseInfo)
	ReturnJson(c, http.StatusBadRequest, http.StatusBadRequest, errMsg, "")
	//终止可能已经被加载的其他回调函数的执行
	c.Abort()
}

// ErrorTokenAuthFail token 权限校验失败
func ErrorTokenAuthFail(c *gin.Context) {
	errMsg, _ := utils.Translater.Translate(consts.TKey_ErrorsNoAuthentication)
	ReturnJson(c, http.StatusUnauthorized, http.StatusUnauthorized, errMsg, "")
	//终止可能已经被加载的其他回调函数的执行
	c.Abort()
}

func ErrorTokenExpired(c *gin.Context) {
	errMsg, _ := utils.Translater.Translate(consts.TKey_ErrorsTokenExpired)
	ReturnJson(c, http.StatusUnauthorized, http.StatusUnauthorized, errMsg, "")
	//终止可能已经被加载的其他回调函数的执行
	c.Abort()
}

// ErrorTokenRefreshFail token不符合刷新条件
func ErrorTokenRefreshFail(c *gin.Context) {
	errMsg, _ := utils.Translater.Translate(consts.TKey_ErrorsRefreshTokenFail)
	ReturnJson(c, http.StatusUnauthorized, http.StatusUnauthorized, errMsg, "")
	//终止可能已经被加载的其他回调函数的执行
	c.Abort()
}

// token 参数校验错误
func TokenErrorParam(c *gin.Context, wrongParam interface{}) {
	errMsg, _ := utils.Translater.Translate(consts.TKey_ValidatorParamsCheckFailMsg)
	ReturnJson(c, http.StatusUnauthorized, consts.ValidatorParamsCheckFailCode, errMsg, wrongParam)
	c.Abort()
}

// ErrorAuthorizationFail 鉴权失败，返回 405 方法不允许访问
func ErrorAuthorizationFail(c *gin.Context, msg interface{}) {
	errMsg, _ := utils.Translater.Translate(consts.TKey_ErrorsNoAuthorization)
	ReturnJson(c, http.StatusOK, http.StatusForbidden, errMsg, msg)
	c.Abort()
}

// ErrorParam 参数校验错误
func ErrorParam(c *gin.Context, wrongParam interface{}) {
	errMsg, _ := utils.Translater.Translate(consts.TKey_ValidatorParamsCheckFailMsg)
	ReturnJson(c, http.StatusOK, consts.ValidatorParamsCheckFailCode, errMsg, wrongParam)
	c.Abort()
}

// ErrorSystem 系统执行代码错误
func ErrorSystem(c *gin.Context, msg string, data interface{}) {
	errMsg, _ := utils.Translater.Translate(consts.TKey_InternalError)
	ReturnJson(c, http.StatusInternalServerError, consts.ServerOccurredErrorCode, errMsg+": "+msg, data)
	c.Abort()
}

// ValidatorError 翻译表单参数验证器出现的校验错误
func ValidatorError(c *gin.Context, err error) {
	errMsg, _ := utils.Translater.Translate(consts.TKey_ValidatorParamsCheckFailMsg)
	if errs, ok := err.(validator.ValidationErrors); ok {
		wrongParam := translater.RemoveTopStruct(errs.Translate(translater.Trans))
		ReturnJson(c, http.StatusBadRequest, consts.ValidatorParamsCheckFailCode, errMsg, wrongParam)
	} else {
		errStr := err.Error()
		// multipart:nextpart:eof 错误表示验证器需要一些参数，但是调用者没有提交任何参数
		if strings.ReplaceAll(strings.ToLower(errStr), " ", "") == "multipart:nextpart:eof" {
			tipMsg, _ := utils.Translater.Translate(consts.TKey_ErrorNotAllParamsIsBlank)
			ReturnJson(c, http.StatusBadRequest, consts.ValidatorParamsCheckFailCode, errMsg, gin.H{"tips": tipMsg})
		} else {
			ReturnJson(c, http.StatusBadRequest, consts.ValidatorParamsCheckFailCode, errMsg, gin.H{"tips": errStr})
		}
	}
	c.Abort()
}
